package com.heima.comment.service.impl;

import com.heima.aliyun.scan.GreenScan;
import com.heima.aliyun.scan.ScanResult;
import com.heima.comment.service.CommentHotService;
import com.heima.comment.service.CommentService;
import com.heima.common.exception.CustException;
import com.heima.feigns.AdminFeign;
import com.heima.feigns.ArticleFegin;
import com.heima.feigns.UserFeign;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.comment.dtos.CommentDTO;
import com.heima.model.comment.dtos.CommentLikeDTO;
import com.heima.model.comment.dtos.CommentSaveDTO;
import com.heima.model.comment.pojos.ApComment;
import com.heima.model.comment.pojos.ApCommentLike;
import com.heima.model.comment.vo.ApCommentVo;
import com.heima.model.common.dtos.ResponseResult;
import com.heima.model.common.enums.AppHttpCodeEnum;
import com.heima.model.threadlocal.AppThreadLocalUtils;
import com.heima.model.user.pojos.ApUser;
import com.heima.utils.common.SensitiveWordUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
@Slf4j
public class CommentServiceImpl implements CommentService {

    @Autowired
    UserFeign userFeign;

    @Autowired
    GreenScan greenScan;

    @Autowired
    AdminFeign adminFeign;

    @Autowired
    ArticleFegin articleFegin;

    @Autowired
    MongoTemplate mongoTemplate;

    @Autowired
    CommentHotService commentHotService;

    @Autowired
    RedissonClient redissonClient;

    /**
     * 保存评论
     * @param dto
     * @return
     */
    @Override
    public ResponseResult saveComment(CommentSaveDTO dto) {
        //校验用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if(user == null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN,"登录后才能评论");
       }
        String content = dto.getContent();
        //自管理敏感词 过滤后的内容
        content = getString(content);
        //使用阿里云检测文本内容
        content = aliyungetString(content);
        Integer userId = user.getId();
        //远程查询当前登录用户信息
        ResponseResult<ApUser> apUserResponseResult = userFeign.findUserById(user.getId());
        if(!apUserResponseResult.checkCode()){
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,"远程调用查询用户信息时出错");
        }
        ApUser apUser = apUserResponseResult.getData();

        // 根据文章id 获取文章信息 需要文章所在频道
        ResponseResult<ApArticle> apArticleResponseResult = articleFegin.findByArticleId(dto.getArticleId());
        if(!apArticleResponseResult.checkCode()){
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR,"远程调用查询文章信息时出错");
        }
        ApArticle article = apArticleResponseResult.getData();
        //创建评论对象
        ApComment apComment = new ApComment();
        apComment.setAuthorId(apUser.getId());
        apComment.setAuthorName(apUser.getName());
        apComment.setArticleId(dto.getArticleId());
        apComment.setType((short)0);
        apComment.setChannelId(article.getChannelId());
        apComment.setContent(content);
        apComment.setImage(apUser.getImage());
        apComment.setLikes(0);
        apComment.setReply(0);
        apComment.setFlag((short)0);
        apComment.setOrd(0);
        apComment.setCreatedTime(new Date());
        apComment.setUpdatedTime(new Date());

        mongoTemplate.save(apComment);
        return ResponseResult.okResult();
    }

    /**
     * 阿里云 检测文本内容
     * @param content 入参 评论内容
     * @return  返回 替换后的结果
     */
    private String aliyungetString(String content) {
        //阿里云校验内容是否违规
        String content1 = content ;
        try {
            ScanResult scanResult = greenScan.greenTextScan(content);
            String suggestion = scanResult.getSuggestion();

            switch (suggestion){
                case "block":
                    //获取到违规信息 替换为 原评论内容
                  content1 = scanResult.getFilteredContent();
                  if(content1 == null){
                   content1 = content;
                  }
                   break;
                case "review":
                    break;
                case "pass":
                    break;
            }
        } catch (Exception e) {
            e.printStackTrace();
            CustException.cust(AppHttpCodeEnum.SERVER_ERROR,"阿里云对评论文本内容校验失败");
        }
        return content1;
    }
    // 查询评论内容中是否有 敏感词 查询敏感库
    private String getString(String content) {
        //远程调用查询管理的敏感词汇
        ResponseResult<List<String>> sensitives = adminFeign.sensitives();
        if(!sensitives.checkCode()){
            log.error("评论保存中 远程调用 查询敏感词时出错了");
            CustException.cust(AppHttpCodeEnum.REMOTE_SERVER_ERROR);
        }
        //获取到敏感词
        List<String> stringList = sensitives.getData();
        //将敏感词 转为DFA 数据模型
        SensitiveWordUtil.initMap(stringList);

        //基于DFA 扫描内容中是否有敏感词汇
        Map<String, Integer> map = SensitiveWordUtil.matchWords(content);
        for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {
            String key = stringIntegerEntry.getKey();
            int length = key.length();
            StringBuilder xx = new StringBuilder();
            for (int i = 0; i < length; i++) {
                xx.append("*");
            }
            content = content.replaceAll(key, xx.toString());
        }
        return content;
    }

    /**
     * 点赞评论 或  取消点赞
     * @param dto
     * @return
     */
    @Override
    public ResponseResult like(CommentLikeDTO dto) {
        //根据评论id 查询评论信息
        Query query = Query.query(Criteria.where("_id").is(dto.getCommentId()));
        ApComment apComment = mongoTemplate.findOne(query, ApComment.class);
        if(apComment == null){
            CustException.cust(AppHttpCodeEnum.DATA_NOT_EXIST,"此评论不存在");
        }
        //获取到当前登录对象
        ApUser user = AppThreadLocalUtils.getUser();
        if(user == null){
            CustException.cust(AppHttpCodeEnum.NEED_LOGIN);
        }

        String commentId = dto.getCommentId();

        RLock lock = redissonClient.getLock("likes-lock");
        lock.lock();
        //判断 是点赞操作还是取消点赞
        //创建返回的点赞数量 map
        Map<String,Object> map = new HashMap<>();
        try {
            //查询对应的评论 信息
            Query query2 = Query.query(Criteria.where("_id").is(dto.getCommentId()));
            ApComment comment = mongoTemplate.findOne(query2, ApComment.class);
            Integer likes = comment.getLikes(); //获取到此评论的点赞数量
            if(dto.getOperation()==0){
                // 为 点赞操作  先查询 是否已经点赞过
                Query apCommentLikeQuery = Query.query(Criteria.where("commentId").is(dto.getCommentId()).and("authorId").is(user.getId()));
                ApCommentLike one = mongoTemplate.findOne(apCommentLikeQuery, ApCommentLike.class);
                if(one != null){
                    CustException.cust(AppHttpCodeEnum.DATA_EXIST,"已经赞过了 不能再赞了");
                }
                //说明没有点赞过 保存点赞行为
                ApCommentLike apCommentLike = new ApCommentLike();
                apCommentLike.setAuthorId(user.getId());
                apCommentLike.setCommentId(dto.getCommentId());
                apCommentLike.setOperation(dto.getOperation());
                mongoTemplate.save(apCommentLike);
                // 修改评论信息的点赞数量加1
                if(comment != null){
                    Update update = new Update();
                    update.set("likes",likes+1);
                    mongoTemplate.updateMulti(query2,update,ApComment.class);
                    map.put("likes",likes+1);
                }
                // 计算热点评论的方法
                if(likes >= 10 && comment.getFlag().intValue() == 0 ){
                    commentHotService.hotCommentExecutor(comment);
                }
            }else if(dto.getOperation() == 1){
                // 为取消点赞行为
                //1. 删除对应的品论点赞 数据
                Query apCommentLikeQuery = Query.query(Criteria.where("commentId").is(dto.getCommentId()).and("authorId").is(user.getId()));
                mongoTemplate.remove(apCommentLikeQuery,ApCommentLike.class);
                //2. 对应的评论信息 点赞数-1
                //判断是否大于0
                if(likes != null && likes >=1){
                    Update update = new Update();
                    update.set("likes", likes-1);
                    mongoTemplate.updateMulti(query2,update,ApComment.class);
                    map.put("likes",likes-1);
                }
            }
        } finally {
            lock.unlock();
        }
        return ResponseResult.okResult(map);
    }

    /**
     * 查询评论列表
     * @param dto
     * @return
     */
    @Override
    public ResponseResult findByArticleId(CommentDTO dto) {
        //校验size  如果为0 设置10
        Integer size = dto.getSize();
        if( size == null ){
            size = 10;
        }

        List<ApComment> apCommentList = null;
        // 判断当前是否是第一页评论
        if(dto.getIndex().intValue() == 1){
            // 查询热点评论集合
            Query with1 = Query.query(Criteria.where("articleId").is(dto.getArticleId()).and("flag").is(1)).with(Sort.by(Sort.Direction.DESC, "likes")).limit(5);
             apCommentList = mongoTemplate.find(with1, ApComment.class);
            size = size-apCommentList.size();

            //查询第一页剩余的普通评论
            Query query = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                    .and("flag").is(0))
                    .with(Sort.by(Sort.Direction.DESC, "createdTime"))
                    .limit(size);
            List<ApComment> apComments = mongoTemplate.find(query, ApComment.class);
            //合并 热点评论和普通评论
            apCommentList.addAll(apComments);
        }else {
            // 根据条件查询 评论列表
            Query with = Query.query(Criteria.where("articleId").is(dto.getArticleId())
                    .and("createdTime").lt(dto.getMinDate())
                    .and("flag").is(0))
                    .with(Sort.by(Sort.Direction.DESC, "createdTime"))
                    .limit(size);
            apCommentList = mongoTemplate.find(with, ApComment.class);
        }
        //判断当前用户是否登录
        ApUser user = AppThreadLocalUtils.getUser();
        if(user == null){
            return ResponseResult.okResult(apCommentList);
        }
        //如果登录了 检查当前评论列表中 哪些评论 登录人点赞过 如果点赞了 将operation 设置为0
        List<ApCommentVo> apCommentVoList = new ArrayList<>();
        for (ApComment apComment : apCommentList) {
            ApCommentVo apCommentVo = new ApCommentVo();
            BeanUtils.copyProperties(apComment,apCommentVo);
            //查询评论 如果 评论点过赞 设置operation 为0
            Query query = Query.query(Criteria.where("authorId").is(user.getId()).and("commentId").is(apComment.getId()));
            ApCommentLike commentLike = mongoTemplate.findOne(query, ApCommentLike.class);
            if(commentLike!= null){
            apCommentVo.setOperation((short)0);
            }
            apCommentVoList.add(apCommentVo);
        }
        return ResponseResult.okResult(apCommentVoList);
    }
}
